You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Bug Fix: NPCs spawned under a target couldn't attack
Summary
NPCs spawned under a target couldn't attack because Interact mode (used for the initial attack interaction) had no logic to step out from under the target, unlike CombatMovement which explicitly handles this case.
Root Cause
When an NPC with allowed_under = false is on the same tile as its target, the following chain of failures occurs:
Step
What Happens
Movement.arrived()
Returns false (overlap check fails)
calculate()
Queues a no-op step (naive destination = current tile when overlapping)
super.tick()
Consumes the no-op step with no movement
cantReach()
Called, interaction is cleared, NPC gives up
Fix
Interact.kt (tick()): Before the normal calculate() / processInteraction() flow, check if the NPC is under its target and not allowed there. If so, mirror CombatMovement.stepOut() behavior:
Clear any stale steps
Pick a random cardinal direction
Queue a step in that direction if passable
Call super.tick() to execute the step
This lets the NPC move out from under the target on the first tick, allowing combat to initialize normally on the second tick.
Test
CombatMovementTest.kt: Creates a guard NPC spawned at the same tile as a player, calls interactPlayer(player, "Attack"), ticks twice, and verifies the NPC has moved away and transitioned to CombatMovement.
Demo
Screencast_20260410_061246.webm
Bug Fix: Character creation screen skipped for new accounts
Summary
New accounts were not shown the character_creation interface on first login.
Root Cause
AccountManager.create() was setting the "creation" timestamp immediately when a new player record was created. Introduction.welcome() uses the presence of "creation" to detect returning players and skip the screen, so new accounts were being mistaken for returning players before they ever logged in.
Fix
Removed "creation" from AccountManager.create(). The timestamp is already set by Introduction.setup() after the character_creation interface closes, which is the correct point in time. Updated the corresponding test to no longer assert the premature value.
Bug Fix: Dragon claws special attack damage and hit timing
Summary
Fixes the dragon claws "Slice and Dice" special attack (DragonClaws.kt) to match the 2011 behavior. There were three damage formula bugs and a fundamental engine-level timing issue causing all four hits to land on the same tick.
Damage Formula Fixes
Scenario
Bug
Fix
4-2-1-1
Hit 1 upper bound was maxHit - 10
Changed to maxHit - 1 (i.e. nextInt(maxHit/2, maxHit))
All scenarios
Hit 4 was hit3 + random(0, 10)
Changed to hit3 + 1, confirmed by documented examples (35-17-8-9, 0-30-15-16, 0-0-22-23)
All-miss
Fallback was random 0 or 10 per hit
Changed to ~2/3 chance of 2 total damage split randomly between hits 3 and 4, ~1/3 true 0-0-0-0
Hit Timing Fix
All four hitsplats were landing on the same tick. The spec requires two pairs: hits 1 & 2 on the activation tick, hits 3 & 4 on the following tick (0.6 seconds later).
Root cause:ActionQueue.tick() runs a while (queue.isNotEmpty()) loop that calls removeIf repeatedly, decrementing remaining on every pass. This fast-forwards any delayed actions within the same tick, so initialDelay = 2 would get decremented to 0 over two passes in a single queue.tick() call, regardless of the delay value passed to hit().
Fix: Instead of passing a delay to the final two hit() calls, hits 3 and 4 are now dispatched from inside a strongQueue proxy action on the target. Because strongQueue adds to pending (not queue), and queuePending() only runs at the start of the next queue.tick(), anything added to pending during an active queue.tick() is naturally deferred by one full tick, with no delay arithmetic needed.
Thanks for the contribution! Admittedly this does need a proper architecture solution but this will be a nice short term fix
Thanks for your feed back, I moved step-out logic from CombatMovement into Movement. Since "step out from under a character target" is a movement concern rather than a combat concern, the logic was moved to Movement (the base class) where it applies to all modes automatically. The shape == -2 guard scopes it to character targets only, and the shouldQueueStepOut() hook lets CombatMovement skip queuing a random step when both characters are already in active combat movement, clearing the stale steps and letting normal recalculation take over instead.
HarleyGilpin
changed the title
Fix: NPCs spawned under a target couldn't attack
fix(2026-04-11): multiple bug fixes to resolve reported user issues
Apr 11, 2026
HarleyGilpin
changed the title
fix(2026-04-11): multiple bug fixes to resolve reported user issues
fix: multiple bug fixes to resolve reported user issues
Apr 11, 2026
HarleyGilpin
changed the title
fix: multiple bug fixes to resolve reported user issues
fix: bugs related to npc movement and player account creation.
Apr 11, 2026
HarleyGilpin
changed the title
fix: bugs related to npc movement and player account creation.
fix: a variety of bugs addressed
Apr 12, 2026
HarleyGilpin
changed the title
fix: a variety of bugs addressed
fix: smashed a variety of user bug reports
Apr 12, 2026
HarleyGilpin
changed the title
fix: smashed a variety of user bug reports
Bug fixes and improvements
Apr 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug Fix: NPCs spawned under a target couldn't attack
Summary
NPCs spawned under a target couldn't attack because Interact mode (used for the initial attack interaction) had no logic to step out from under the target, unlike
CombatMovementwhich explicitly handles this case.Root Cause
When an NPC with
allowed_under = falseis on the same tile as its target, the following chain of failures occurs:Movement.arrived()false(overlap check fails)calculate()super.tick()cantReach()Fix
Interact.kt(tick()): Before the normalcalculate()/processInteraction()flow, check if the NPC is under its target and not allowed there. If so, mirrorCombatMovement.stepOut()behavior:super.tick()to execute the stepThis lets the NPC move out from under the target on the first tick, allowing combat to initialize normally on the second tick.
Test
CombatMovementTest.kt: Creates a guard NPC spawned at the same tile as a player, callsinteractPlayer(player, "Attack"), ticks twice, and verifies the NPC has moved away and transitioned toCombatMovement.Demo
Screencast_20260410_061246.webm
Bug Fix: Character creation screen skipped for new accounts
Summary
New accounts were not shown the
character_creationinterface on first login.Root Cause
AccountManager.create()was setting the"creation"timestamp immediately when a new player record was created.Introduction.welcome()uses the presence of"creation"to detect returning players and skip the screen, so new accounts were being mistaken for returning players before they ever logged in.Fix
Removed
"creation"fromAccountManager.create(). The timestamp is already set byIntroduction.setup()after thecharacter_creationinterface closes, which is the correct point in time. Updated the corresponding test to no longer assert the premature value.Bug Fix: Dragon claws special attack damage and hit timing
Summary
Fixes the dragon claws "Slice and Dice" special attack (
DragonClaws.kt) to match the 2011 behavior. There were three damage formula bugs and a fundamental engine-level timing issue causing all four hits to land on the same tick.Damage Formula Fixes
maxHit - 10maxHit - 1(i.e.nextInt(maxHit/2, maxHit))hit3 + random(0, 10)hit3 + 1, confirmed by documented examples (35-17-8-9,0-30-15-16,0-0-22-23)0or10per hit0-0-0-0Hit Timing Fix
All four hitsplats were landing on the same tick. The spec requires two pairs: hits 1 & 2 on the activation tick, hits 3 & 4 on the following tick (0.6 seconds later).
Root cause:
ActionQueue.tick()runs awhile (queue.isNotEmpty())loop that callsremoveIfrepeatedly, decrementingremainingon every pass. This fast-forwards any delayed actions within the same tick, soinitialDelay = 2would get decremented to 0 over two passes in a singlequeue.tick()call, regardless of the delay value passed tohit().Fix: Instead of passing a delay to the final two
hit()calls, hits 3 and 4 are now dispatched from inside astrongQueueproxy action on the target. BecausestrongQueueadds topending(notqueue), andqueuePending()only runs at the start of the nextqueue.tick(), anything added topendingduring an activequeue.tick()is naturally deferred by one full tick, with no delay arithmetic needed.